#include "CMemoryStream.h"
#include <string.h>
namespace lampe{
namespace stream{

#define Cache_Size 16
#define PVoid(data,position) &((irr::c8*)data)[position]

u32 CMemoryStream::position(){
	return Position;
}

void CMemoryStream::position(u32 p){
	Position=p;
}

u32 CMemoryStream::size(){
	return uses;
}

bool CMemoryStream::eof(){
}

u32 CMemoryStream::read(void* buffer, u32 size){
	memcpy(buffer,PVoid(Data,position()),size);
	Position+=size;
}

u32 CMemoryStream::write(void* buffer, u32 size){
	if (buffer==0){
		if (free_on_destroy && Data!=0){
			delete[]Data;
		}
		Data=new irr::u8[size];
		allocated=size;
		uses=size;
		Position=0;
		free_on_destroy=true;
	}else{
		checkSize(size);
		memcpy(PVoid(Data,position()),buffer,size);
		Position+=size;
	}
}

void CMemoryStream::checkSize(irr::u32 needSize){
	int add=position()+needSize-allocated;
	if (add<=0){
		return;
	}
	uses+=needSize;
	irr::u8 block_count=ceil(needSize/Cache_Size);
	allocated=block_count*Cache_Size;
	void*newData=new irr::u8[allocated];
	if (Data!=0){
		memcpy(PVoid(newData,0),PVoid(Data,0),uses);
	}
	if (free_on_destroy && Data!=0){
		delete[]Data;
	}
	free_on_destroy=true;
	Data=newData;
}

void*CMemoryStream::data(){
	return Data;
}
void CMemoryStream::data(void*begin,irr::u32 size,bool _free_on_destroy){
	if (free_on_destroy && Data!=0){
		delete[]Data;
	}
	Data=begin;
	allocated=size;
	uses=size;
	free_on_destroy=_free_on_destroy;
	Position=0;
	if (begin==0){
		begin=new irr::u8[size];
		free_on_destroy=true;
	}
}
void CMemoryStream::clear(){
	if (free_on_destroy && Data!=0){
		delete[]Data;
	}
	Data=0;
	allocated=0;
	uses=0;
	Position=0;
}

CMemoryStream::CMemoryStream():allocated(0),uses(0),Data(0),free_on_destroy(false),Position(0){
	//
}
CMemoryStream::~CMemoryStream(){
	clear();
}

IMemoryStream*createMemoryStream(){
	return new CMemoryStream();
}

}//namespace stream
}//namespace lampe
